package com.xj.demo.controller;

import com.xj.demo.entity.EsBlog;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.List;
import java.util.stream.Collectors;
import org.elasticsearch.index.query.MoreLikeThisQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms.Bucket;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.query.StringQuery;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * <p> esblog api </p>
 *
 * @author xujj
 * @description
 * @date 2024/4/6 17:38
 */

@RequestMapping("/es")
@Api(value = "ElasticSearch相关接口", tags = {"ElasticSearch相关接口"})
@RestController
public class EsBlogController {


    private final ElasticsearchOperations elasticsearchOperations;

    @Autowired
    public EsBlogController(ElasticsearchOperations elasticsearchOperations) {
        this.elasticsearchOperations = elasticsearchOperations;
    }


    @PostMapping("/saveBlog")
    @ApiOperation(value = "保存博客", notes = "保存博客")
    public String save(@RequestBody EsBlog esBlog) {
        EsBlog blog = elasticsearchOperations.save(esBlog, IndexCoordinates.of("blog"));
        return "success";
    }

    @PostMapping("/saveAllBlog")
    @ApiOperation(value = "批量保存博客", notes = "批量保存博客")
    public String saveAll(@RequestBody List<EsBlog> list) {
        List<IndexQuery> indexQueries = list.stream()
                .map(esBlog -> new IndexQueryBuilder()
                        .withId(esBlog.getId().toString())
                        .withObject(esBlog)
                        .build())
                .collect(Collectors.toList());
        elasticsearchOperations.bulkIndex(indexQueries, IndexCoordinates.of("blog"));
        return "success";
    }


    @GetMapping("/deleteBlogById")
    @ApiOperation(value = "通过id删除博客", notes = "通过id删除博客")
    public String deleteBlogById(String id) {
        return elasticsearchOperations.delete(id, IndexCoordinates.of("blog"));
    }


    @GetMapping("/deleteBlogByType/{type}")
    @ApiOperation(value = "通过type删除博客", notes = "通过type删除博客")
    public String deleteBlogByType(Integer type) {
        String blog = elasticsearchOperations.delete(type, IndexCoordinates.of("blog"));
        return blog;
    }



    /**------------  StringQuery的使用----------------------**/
    @GetMapping("/StringQuery")
    @ApiOperation(value = "StringQuery", notes = "StringQuery")
    public List<EsBlog> StringQuery() {
        Query query = new StringQuery("{ \"match\": { \"content\": { \"query\": \"三\" } } } ");
        SearchHits<EsBlog> searchHits = elasticsearchOperations.search(query, EsBlog.class);
        return searchHits.getSearchHits().stream()
                .map(hit -> hit.getContent())
                .collect(Collectors.toList());
    }


    /**------------ NativeSearchQuery的使用----------------------**/
    @GetMapping("/searchBlogByKey")
    @ApiOperation(value = "通过关键字搜索博客", notes = "通过关键字搜索博客")
    public SearchHits<EsBlog> searchBlogByKey(@RequestParam String keywords) {
        //构建查询，执行查询
        Query searchQuery = new NativeSearchQueryBuilder().
                withQuery(QueryBuilders.multiMatchQuery(keywords, "title", "content", "summary"))
                .build();
        //执行查询，获取结果
        SearchHits<EsBlog> search = elasticsearchOperations.search(searchQuery, EsBlog.class);
        return search;
    }

    @GetMapping("/findAllBlogs")
    @ApiOperation(value = "查询所有博客", notes = "查询所有博客")
    public List<EsBlog> findAll() {
        SearchHits<EsBlog> search = elasticsearchOperations.search(new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.matchAllQuery()).build(), EsBlog.class);
        List<EsBlog> list = search.getSearchHits().stream().map(a -> a.getContent()).collect(Collectors.toList());
        return list;
    }

    @GetMapping("/searchBlogPage")
    @ApiOperation(value = "查询所有博客分页显示", notes = "查询所有博客分页显示")
    public SearchHits<EsBlog> searchBlogPage(@RequestParam(name = "currentPage", required = false, defaultValue = "1") Integer
            currentPage,
            @RequestParam(name = "pageSize", required = false, defaultValue = "10") Integer
                    pageSize) {

        Pageable pageable = PageRequest.of(currentPage - 1, pageSize);
        //构建查询，执行查询
        Query searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.matchAllQuery())
                .withPageable(pageable)
                .build();
        //执行查询，获取结果
        SearchHits<EsBlog> search = elasticsearchOperations.search(searchQuery, EsBlog.class);
        return search;
    }

    /**
     * 通过关键字搜索博客内容且高亮显示关键字
     *
     * @param keywords
     * @return
     */
    @PostMapping("/queryWithHighlight")
    @ApiOperation(value = "通过关键字搜索博客内容且高亮显示关键字", notes = "通过关键字搜索博客内容且高亮显示关键字")
    public SearchHits<EsBlog> queryWithHighlight(@RequestParam String keywords) {

        HighlightBuilder highlightBuilder = new HighlightBuilder().field("content")
                .preTags("<em style='color:red'>")
                .postTags("</strong>")
                .fragmentSize(200) // 高亮片段的大小
                .numOfFragments(3);// 返回的高亮片段数量;
        //构建查询，执行查询
        Query searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.multiMatchQuery(keywords, "content"))
                .withHighlightBuilder(highlightBuilder)
                .build();
        //执行查询，获取结果
        SearchHits<EsBlog> search = elasticsearchOperations.search(searchQuery, EsBlog.class);
        return search;
    }

    @GetMapping("/searchCountTermType")
    @ApiOperation(value = "聚合查询", notes = "聚合查询")
    public List<? extends Bucket> searchCountTermType() {
        //构建查询，执行查询
        Query searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.matchAllQuery())
                .addAggregation(AggregationBuilders.terms("type")//聚合名
                        .field("type.keyword")// 聚合的字段
                        .size(10))// 返回的桶的最大数量
                .build();
        //执行查询，获取结果
        SearchHits<EsBlog> search = elasticsearchOperations.search(searchQuery, EsBlog.class);
        // 获取聚合结果
        Terms types = search.getAggregations().get("type");
        List<? extends Bucket> buckets = types.getBuckets();
        System.out.println("<============================>");
        // 处理聚合结果
        for (Terms.Bucket bucket : buckets) {
            String key = bucket.getKeyAsString(); // 聚合的键（即type字段的值）
            long docCount = bucket.getDocCount(); // 文档计数
            System.out.println("Type: " + key + ", Count: " + docCount);
        }
        return buckets;
    }

    /**
     * 根据内容搜索相似文档的查询,可以推荐相似内容给用户
     * @param text
     * @return
     */
    @GetMapping("/searchMoreLikeThis")
    @ApiOperation(value = "根据内容搜索相似文档的查询", notes = "根据内容搜索相似文档的查询")
    public List<EsBlog> searchMoreLikeThis(String text) {
        //构建查询
        MoreLikeThisQueryBuilder queryBuilder = new MoreLikeThisQueryBuilder(new String[]{"content"}, new String[]{text}, null)
                .minTermFreq(2)
                .minDocFreq(2);

        Query searchQuery = new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .build();
        //执行查询，获取结果
        SearchHits<EsBlog> searchHits = elasticsearchOperations.search(searchQuery, EsBlog.class);
        return searchHits.getSearchHits().stream()
                .map(hit -> {
                    EsBlog content = hit.getContent();
                    //...
                    return content;
                })
                .collect(Collectors.toList());
    }

}
